package org.xhy.hrm.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.xhy.hrm.domain.CourseType;
import org.xhy.hrm.dto.CourseCrumbsDto;
import org.xhy.hrm.mapper.CourseTypeMapper;
import org.xhy.hrm.service.ICourseTypeService;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 课程目录 服务实现类
 * </p>
 *
 * @author xhy
 * @since 2021-09-14
 */
@Service
public class CourseTypeServiceImpl extends ServiceImpl<CourseTypeMapper, CourseType> implements ICourseTypeService {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;


    /**
     * 覆写增删改方法，加上删除缓存
     * @param entity
     * @return
     */
    @Override
    @CacheEvict(cacheNames = "course-alltype",key = "'all'") //增删改方法上，只需要正常操作即可，这个注解会帮我们删除缓存,key值不是一个字符串，必须加上单引号
    public boolean insert(CourseType entity) {
        boolean success = super.insert(entity);
        //如果操作成功则删除缓存，避免出现脏数据就
//        if (success){
//            redisTemplate.delete("course-alltype");
//        }
        return success;
    }

    @Override
    @CacheEvict(cacheNames = "course-alltype",key = "'all'") //增删改方法上，只需要正常操作即可，这个注解会帮我们删除缓存
    public boolean deleteById(Serializable id) {
        return super.deleteById(id);
    }

    @Override
    @CacheEvict(cacheNames = "course-alltype",key = "'all'")
    public boolean updateById(CourseType entity) {
        boolean success = super.updateById(entity);
        //如果操作成功则删除缓存，避免出现脏数据就
//        if (success){
//            redisTemplate.delete("course-alltype");
//        }
        return success;
    }

    //Cache自动化缓存
    @Override
    @Cacheable(cacheNames = "course-alltype",key = "'all'") //查询方法上，只需要正常查询即可，这个注解会帮我们做缓存
    public List<CourseType> treeData() {

        //返回即可
        return toTreeData(baseMapper.selectList(null));
    }

    //手动缓存备份
    public List<CourseType> treeData2() {
        //查询缓存中是否有数据
        List<CourseType> allTypeList = (List<CourseType>) redisTemplate.opsForValue().get("course-alltype");
        //如果有直接返回
        if (allTypeList != null){
            return toTreeData(allTypeList);
        }
        //如果没有从数据库查询
        List<CourseType> typeList = baseMapper.selectList(null);
        //保存到缓存中
        redisTemplate.opsForValue().set("course-alltype",typeList,12, TimeUnit.HOURS);
        //返回
        return toTreeData(typeList);
    }


    /**
     * 思路：首先查询出所有的课程类型集合，通过判断Pid是否为0确定一级菜单，添加到集合中，其他的二级菜单继续循环追加
     * 注意！集合中存储的对象地址！在堆中，两个集合中的一级菜单都是同一个对象
     * @return
     */
    public List<CourseType> toTreeData(List<CourseType> allTypeList) {
        //查询出所有的课程分类
        List<CourseType> typeList = baseMapper.selectList(null);

        //map优化
        Map<Long,CourseType> typeMap = new HashMap<>();
        //遍历,id作为key,元素作为value
        typeList.forEach(courseType -> {
            typeMap.put(courseType.getId(),courseType);
        });

        //一级集合
        List<CourseType> firstCourseTypes = new ArrayList<>();
        //循环所以的课程分类
        typeList.forEach(courseType -> {
            //通过pid=0查询一级菜单
            if (courseType.getPid()==null || courseType.getPid().intValue()==0){
                firstCourseTypes.add(courseType);
            }else {
                //通过pid查询所有的元素
                CourseType parentType = typeMap.get(courseType.getPid().longValue());
                if (parentType!=null){
                    //加入自己的父级类型
                    parentType.getChildren().add(courseType);
                }

                /*//找到父类型
                for (CourseType parentType : typeList){
                    if (courseType.getPid().longValue() == parentType.getId().longValue()){
                        //加入自己的父级类型
                        parentType.getChildren().add(courseType);
                        break;
                    }
                }*/
            }
        });
        return firstCourseTypes;
    }

    /**
     * 面包屑
     *  思路：
     *      1.通过id查询到自己分类
     *      2.再查询path,循环查出自己的同级和其他级
     *      3.再批量查询
     * @param id
     * @return
     */
    @Override
    public List<CourseCrumbsDto> crumbs(Long id) {
        List<CourseCrumbsDto> crumbsDtos = new ArrayList<>();
        //先通过id查询当前分类
        CourseType courseType = baseMapper.selectById(id);
        //拿到path
        String paths = courseType.getPath(); //(111.111.111)
        //分割path，拿到path数据
        String[] path = paths.split("\\.");
        //批量查询拿到分类集合
        List<CourseType> courseTypes = baseMapper.selectBatchIds(Arrays.asList(path));
        //循环遍历
        courseTypes.forEach(type -> {
            //创建临时对象
            CourseCrumbsDto courseCrumbsDto = new CourseCrumbsDto();
            //将自己分类设置进去
            courseCrumbsDto.setOwnerCourseType(type);

            //查询出自己的同类
            EntityWrapper<CourseType> wrapper = new EntityWrapper<>();
            wrapper.eq("pid",type.getPid()); //相当于 sql中where pid = #{pid}
            List<CourseType> otherCourseTypes = baseMapper.selectList(wrapper);

            //把自己删掉
            otherCourseTypes.remove(type);

            //将其他分类设置进去
            courseCrumbsDto.setOtherCourseTypes(otherCourseTypes);

            //将数据设置进CourseCrumbsDto
            crumbsDtos.add(courseCrumbsDto);
        });
        return crumbsDtos;
    }
}
